import inspect
from collections import namedtuple
from functools import wraps
from typing import Callable, TypeVar

from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse

RT = TypeVar('RT')  # 返回类型

HttpCode = namedtuple('HttpResp', ['code', 'message'])


class HttpResp:
    """HTTP响应结果
    """
    SUCCESS = HttpCode(200, '成功')
    FAILED = HttpCode(400, '失败')
    PARAMS_VALID_ERROR = HttpCode(422, '参数校验错误')
    PARAMS_TYPE_ERROR = HttpCode(400, '参数类型错误')
    REQUEST_METHOD_ERROR = HttpCode(405, '请求方法错误')
    ASSERT_ARGUMENT_ERROR = HttpCode(400, '断言参数错误')

    LOGIN_ACCOUNT_ERROR = HttpCode(401, '用户名或密码错误')
    LOGIN_DISABLE_ERROR = HttpCode(403, '当前账户已被禁止登录')
    TOKEN_EMPTY = HttpCode(401, '未提供token或无效')
    TOKEN_INVALID = HttpCode(401, '无效token')

    NO_PERMISSION = HttpCode(403, '无相关权限')
    REQUEST_404_ERROR = HttpCode(404, '请求接口不存在')

    SYSTEM_ERROR = HttpCode(500, '系统错误')
    SYSTEM_TIMEOUT_ERROR = HttpCode(504, '请求超时')


def unified_resp(func: Callable[..., RT]) -> Callable[..., RT]:
    """统一响应格式
        接口正常返回时,统一响应结果格式
    """

    @wraps(func)
    async def wrapper(*args, **kwargs) -> RT:
        if inspect.iscoroutinefunction(func):
            resp = await func(*args, **kwargs) or []
        else:
            resp = func(*args, **kwargs) or []
        return JSONResponse(
            content=jsonable_encoder(
                # 正常请求响应
                {'code': HttpResp.SUCCESS.code, 'message': HttpResp.SUCCESS.message, 'data': resp},
                by_alias=False),
            media_type='application/json;charset=utf-8'
        )

    return wrapper
